package atlantik.game;

import modelz.IdMap;
import modelz.UpdateListener;
import atlantik.game.action.BoundAction;
import atlantik.game.action.BoundActionFactory;

public class Game extends AtlantikIdHolder<Integer, Game> {

	private String name;

	private String description;

	private boolean canBeJoined;

	private int players;

	private int minPlayers;

	private int maxPlayers;

	private Player master;

	private Status status = Status.NONE;

	private final IdMap<String, Option> options;

	public Game(Atlantik client) {
		super(client);
		options = new IdMap<String, Option>(client);
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public boolean canBeJoined() {
		return canBeJoined;
	}

	public int getPlayers() {
		return players;
	}

	public int getMinPlayers() {
		return minPlayers;
	}

	public int getMaxPlayers() {
		return maxPlayers;
	}

	public Player getMaster() {
		return master;
	}

	public Status getStatus() {
		return status;
	}

	public IdMap<String, Option> options() {
		return options;
	}

	void setName(String name) {
		this.name = name;
	}

	void setDescription(String description) {
		this.description = description;
	}

	void setCanBeJoined(boolean canBeJoined) {
		this.canBeJoined = canBeJoined;
	}

	void setPlayers(int players) {
		this.players = players;
	}

	void setMinPlayers(int minPlayers) {
		this.minPlayers = minPlayers;
	}

	void setMaxPlayers(int maxPlayers) {
		this.maxPlayers = maxPlayers;
	}

	void setMaster(Player master) {
		this.master = master;
	}

	void setStatus(Status status) {
		this.status = status;
	}

	static Class<Option> getOptionClass(String type) {
		if ("bool".equals(type))
			return Option.class;
		return null;
	}

	public static enum Status {
		CONFIG("config"), INIT("init"), RUNNING("run"), ENDED("end"), NONE(
				"none");

		public final String value;

		private Status(String value) {
			this.value = value;
		}
	}

	static final Status statusFromString(String status) {
		for (Status s : Status.values())
			if (s.value.equals(status))
				return s;
		return Status.NONE;
	}

	static interface Value<T> {
		void setValue(T value);

		T getValue();
	}

	public static interface BooleanValue extends Value<Boolean> {
	}

	public static class Option extends AtlantikIdHolder<String, Option>
			implements BooleanValue {
		public static final BoundActionFactory<ChangeAction, Option> CHANGE = new BoundActionFactory<ChangeAction, Option>() {
			public ChangeAction getActionInstance(Atlantik client, Option item) {
				return new ChangeAction(client, item);
			}
		};

		private String title;

		private boolean canEdit;

		protected String value;

		public Option(Atlantik client) {
			super(client);
		}

		public String getTitle() {
			return title;
		}

		public boolean canEdit() {
			return canEdit;
		}

		protected void setCanEdit(boolean canEdit) {
			this.canEdit = canEdit;
		}

		protected void setTitle(String title) {
			this.title = title;
		}

		protected void setValue(String value) {
			this.value = value;
		}

		public void setValue(Boolean value) {
			setValue((value ? "1" : "0"));
		}

		public Boolean getValue() {
			return "1".equals(value);
		}

		public static class ChangeAction extends
				BoundAction<ChangeAction, Option> {

			protected ChangeAction(Atlantik client, Option item) {
				super(client, item);
				self().getGame().addListener(new UpdateListener<Game>() {
					public void updated(Game item) {
						update();
					}
				});
			}

			@Override
			public boolean canPerform() {
				if( !super.canPerform() || !item.canEdit() )
					return false;
				Game game = self().getGame();
				if( game == null )
					return false;
				return self().equals(game.getMaster());
			}

			@Override
			public void perform() {
				client.command(getToggleCommand());
			}

			public String getToggleCommand() {
				return item.getId() + (item.getValue() ? "0" : "1");
			}

			public boolean isChecked() {
				return item.getValue();
			}

			@Override
			public String getCaption() {
				return item.getTitle();
			}

			public boolean isSelected() {
				return item.getValue();
			}
		};
	}

}
